<?php
/**
 ***********************************************************************************************************************
 * 快捷快递接口统一基础类
 * 快捷开放平台：http://cp.kjkd.com
 * @author ldh
 ***********************************************************************************************************************
 */
namespace soa\partner\kj;

use artisan\cache;
use artisan\http;
use soa\client;

class KjClient extends client
{
    const USER_CODE = 'kuaibao';//http://cp.kjkd.com 登录账号

    const PASSWORD = 'kuaidihelp269';//http://cp.kjkd.com 登录密码

    const KEY = '306ab298f801acaa05000ca03b9d6d50';//http://cp.kjkd.com/view.action 秘钥

    const MANUFACTURER = 'kuaibao';

    const API_LOGIN = 'PDA_EMP_PASSWD_LOGIN';//登录

    const API_UPLOAD = 'PDA_DATA_UPLOAD';//巴枪上传

    const API_PROBLEM_TYPE = 'PDA_UPDATE_PROBLEM_TYPE';//更新问题件类型

    const API_RULE = 'PDA_UPDATE_BILL_RULE';//更新单号扫描规则

    const API_SITE_MONEY = 'PDA_CHECK_SITE_MONEY';//网点预付款更新

    private $typeMap = [
        self::API_LOGIN,
        self::API_UPLOAD,
        self::API_PROBLEM_TYPE,
        self::API_RULE,
        self::API_SITE_MONEY,
    ];

    protected $service_url = 'http://api.kjkd.com:8084/KDT/cp_message_receiver.do';//测试地址

//    protected $service_url = 'http://115.231.73.55:8080/KDT/cp_order_receiver.do';//正式地址

    protected $service_name = 'kj_api';

    protected $_timeout = 5;

    protected $api = '';

    /**
     * 登录统一入口
     *
     * @param $code
     * @param $password
     * @return array
     */
    public final function login($code, $password)
    {
        $this->_timeout = 5;

        if(empty($code) || empty($password)){
            raise(1009);
        }

        $result = $this->send(self::API_LOGIN, [
            'phone'        => $code,//手机号或工号
            'password'     => $password,
            'ver'          => '4.0',
            'manufacturer' => self::MANUFACTURER,
        ]);

        if(!empty($result['openState'])){//0启用，1禁用
            self::$_code = 1002;
            self::$_msg = '该工号被禁用！';
            return [];
        }
        return $result;
    }

    /**
     * 巴枪数据上传
     *
     * @param $scanData
     * @param $scanInfo
     * @param $devId
     * @return array
     */
    public final function upload($scanData, $scanInfo, $devId)
    {
        if(empty($scanData) || empty($scanInfo) || empty($devId)){
            return false;
        }

        return $this->send(self::API_UPLOAD, [
            'ver'          => '1.0',
            'sys_sn'       => $devId,
            'key'          => '',
            'manufacturer' => self::MANUFACTURER,
            'uCompany'     => $scanInfo['branch_code'],
            'dataLength'   => mb_strlen($scanData, 'UTF-8'),
            'scanData'     => $scanData,//每条数据用\r\n分隔开
        ]);
    }

    /**
     * 通用接口
     *
     * @param $api
     * @param array $data
     * @param array $options
     * @return array
     */
    public function send($api, $data = [], $options = [])
    {
        if(!in_array($api,$this->typeMap)){
            raise(1009,'api非法！');
        }

        $this->_reset();

        $this->setHttpOption($options);

        $data = json_encode($data);

        $logisticsInterface = [
            'api'         => $this->api = $api,
            'userCode'    => self::USER_CODE,
            'passWord'    => md5(self::PASSWORD),
            'data'        => urlencode($data),
            'data_digest' => md5($data . self::KEY),
        ];

        $post = [
            'logistics_interface' => json_encode($logisticsInterface)
        ];
//var_dump($post);
        return $this->post($this->api, $post);
    }

    /**
     * @param $api
     * @param array $data
     * @param string $type
     * @return array
     */
    protected function request($api, $data = [], $type = 'POST')
    {
        if(empty($api) || empty($this->service_url) || empty($type)) {
            return [];
        }

        $time1 = time();

        $option = $this->getHttpOption();

        empty($option['TIMEOUT']) and $option['TIMEOUT'] = $this->_timeout;

        switch ($type) {
            case 'POST':
                $response = http::post($this->service_url, $data, $option);
                break;
            case 'GET':
            default:
                $response = http::get($this->service_url, $data, $option);
                break;
        }
        $this->response = $response;

        $ret = $this->parse($response, 'errorCode', 'errorMsg', 'data');
        self::$_result = $response;

        self::$_msg   = $ret->msg;
        self::$_code  = $ret->code;
        self::$_error = $ret->error;

        if($ret->error !== 0) {
            if(is_numeric($ret->error) && $this->getCode() < 1009) {
                $time2 = time();
                logDebug('[' . $api . ']' . $ret->msg . '耗时：'.($time2-$time1).' response:'.(is_string($response)?$response:json_encode($response,JSON_UNESCAPED_UNICODE)).' request:'.(is_string($data)?$data:json_encode($data,JSON_UNESCAPED_UNICODE )), $api, $this->service_name);// 注：记录客户端名称（即项目名称）、错误消息、错误的接口（左侧不带/）、服务名称
            }
        }

        return self::$_data = $ret->data;
    }

    /**
     * @param string $result
     * @param string $code
     * @param string $msg
     * @param string $data
     * @return mixed
     */
    protected function parse($result = '', $code = 'errorCode', $msg = 'errorMsg', $data = 'data')
    {
        $this->_reset($result);

        $json = json_decode('{"error":0,"msg":"成功","code":0}');

        $json->data = '';

        if(empty($result)) {
            $json->error += 1;
            $json->msg = '网络忙，请稍后重试[该服务或接口无返回]!';
            $json->code = 1000;
            return $json;
        }

        $arr = json_decode($result, true);
        if(json_last_error() != 0) {
            $json->error += 1;
            $json->msg = '该服务或接口返回结果无法解析:' . json_last_error() . (string)json_last_error_msg();
            $json->code = 422;
            return $json;
        }

        if(empty($arr['success']) || !isset($arr[$code]) || !empty($arr[$code])) {
            $json->error += 1;
            $json->msg = !empty($arr[$msg]) ? $arr[$msg] : '该服务或接口返回未知状态错误!';
            $json->code = !isset($arr[$code]) ? 1020 : $arr[$code];
            if(isset($arr[$data])) {
                $json->data = $arr[$data];
            }
            return $json;
        }

        $json->code = 0;
        if(isset($arr[$data])) {
            $json->data = $arr[$data];
        }
        return $json;
    }

    /**
     * @var array
     */
    protected $_option = [];

    /**
     * @param array $option
     */
    public function setHttpOption(array $option)
    {
        $option and $this->_option = $option;
    }

    /**
     * @return mixed
     */
    public function getHttpOption()
    {
        return $this->_option;
    }

    /**
     * @var \artisan\cache;
     */
    protected $cache;

    /**
     * @var
     */
    protected $cacheKey;

    /**
     * @param $key
     * @param string $key1
     * @return string
     */
    public function keyBuilder($key, $key1 = '')
    {
        $this->cache = cache::connect('pda');
        if($key && is_string($key)){
            $this->cacheKey = 'zzzzz_kj_' . ucfirst($key);
            if($key1){
                $this->cacheKey = $this->cacheKey . $key1;
            }
        }
        return $this->cacheKey;
    }

    /**
     * @param $forceUpdate
     * @return array|bool|mixed|null|string
     */
    public function getRule($forceUpdate = false)
    {
        $this->keyBuilder(__FUNCTION__);
        if(empty($forceUpdate)){
            $return = $this->cache->get($this->cacheKey);
        }

        if(empty($return) || !is_string($return)){
            $result = $this->kjRule();
            $return = [];
            if($result && is_array($result)){
                foreach($result as $item){
                    if(!empty($item['baseCode']) && !empty($item['baseValue'])){
                        $return[] = $item;
                    }
                }
                $return and $this->cache->set($this->cacheKey, $return, 3600);
            }
        }

        return $return;
    }

    /**
     * @return array|bool|mixed|null|string
     */
    public function getQuestionList()
    {
        $this->keyBuilder(__FUNCTION__);
        $return = $this->cache->get($this->cacheKey);
        $copyKey = 'copy:' . $this->cacheKey;
        if(empty($return) || !is_array($return)){
            $result = $this->questionList();
            $return = [];
            if($result && is_array($result)){
                foreach($result as $item){
                    if(!empty($item['problemCode']) && !empty($item['problemName'])){
                        $return[$item['problemCode']] = [
                            'badWayBillCode' => $item['problemCode'],
                            'badWayBillDesc' => $item['problemName'],
                        ];
                    }
                }
                if($return) {
                    $this->cache->set($this->cacheKey, $return, 3600);
                    $this->cache->set($copyKey, $return, 86400*3);
                }
            }
            if(empty($return)){
                $return = $this->cache->get($copyKey);
                if($return && is_array($return)){
                    return $return;
                }
            }
        }

        return $return;
    }

    /**
     * 运单号规则
     *
     * @return array
     */
    public function kjRule()
    {
        return $this->send(self::API_RULE,[
            'ver'          => '1.0',
            'manufacturer' => self::MANUFACTURER,
            'sys_sn'       => '',
            'key'          => '',
        ]);
    }

    /**
     * 问题件原因
     *
     * @return array
     */
    public function questionList()
    {
        return $this->send(self::API_PROBLEM_TYPE,[
            'ver'          => '1.0',
            'manufacturer' => self::MANUFACTURER,
            'sys_sn'       => '',
            'key'          => '',
        ]);
    }

    /**
     * 网点预付款更新
     *
     * @param $siteCode
     * @return array
     */
    public function siteMoney($siteCode)
    {
        if(empty($siteCode)){
            return [];
        }

        return $this->send(self::API_SITE_MONEY,[
            'ver'          => '1.0',
            'manufacturer' => self::MANUFACTURER,
            'sys_sn'       => '',
            'key'          => '',
            'uCompany'     => $siteCode,
        ]);
    }
}